﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.Media;
using Net.TheBoredCoders.SoundBoard.Controls;

namespace Net.TheBoredCoders.SoundBoard
{
    public static class HelperClass
    {
        #region Content Reader

        /// <summary>
        /// Reads the content directory - Entry-Point for this Action.
        /// </summary>
        /// <param name="basePath">The base path.</param>
        /// <returns>a SampleData Object containing the Data from the root-directory</returns>
        public static SampleData ReadContentDirectory(string basePath)
        {
            // create base-object
            SampleData rootDir = new SampleData();
            rootDir.DataType = DataType.Directory;
            rootDir.Name = Properties.Settings.Default.Label_RootDir;
            rootDir.Path = basePath;
            // fill with files and subdirs
            rootDir.ChildElements = loadDirectoryContent(basePath);
            // return the Object for further processing in application
            return rootDir;
        }

        /// <summary>
        /// Loads the content of a directory.
        /// </summary>
        /// <param name="path">The path.</param>
        /// <returns>List with Samples and Directoies in teh Directory</returns>
        private static List<SampleData> loadDirectoryContent(string path)
        {
            // prepare result-list
            List<SampleData> resultList = new List<SampleData>();
            // read files in directory
            String[] files = System.IO.Directory.GetFiles(path);
            foreach (String file in files) // check all files in directory
            {
                if (System.IO.Path.GetExtension(file).ToLower() == ".wav") // if filetype matches (.wav)
                {
                    // create Sample-Item and add sample-item to list
                    resultList.Add(createSampleDataFromFile(file));
                }
            }
            // read sub-dirs
            String[] directories = System.IO.Directory.GetDirectories(path);
            foreach (String directory in directories) // check all sub-directories in directory
            {
                SampleData tmpDirectory = new SampleData();
                // create new dir-item
                tmpDirectory.DataType = DataType.Directory;
                tmpDirectory.Path = directory;
                // extract name of last folder in path, insert spaces (if configured) and apply it as name
                tmpDirectory.Name = InsertSpaces(directory.Substring(directory.LastIndexOf(@"\") + 1));
                // fill sub-folder list
                tmpDirectory.ChildElements = loadDirectoryContent(directory);
                // add dir to list of items
                resultList.Add(tmpDirectory);
            }
            // return the result
            return resultList;
        }

        /// <summary>
        /// Creates the sample data from file(s).
        /// </summary>
        /// <param name="file">The sample file path.</param>
        /// <returns></returns>
        private static SampleData createSampleDataFromFile(string file)
        {
            // create Sample-Item
            SampleData resultData = new SampleData();
            // fill sample-item
            resultData.DataType = DataType.Sample;
            resultData.Path = file;
            // create name
            resultData.Name = InsertSpaces(System.IO.Path.GetFileNameWithoutExtension(file));
            // check for details (.txt file)
            string detailsFile = getPathWithoutExtension(file) + ".txt";
            if (System.IO.File.Exists(detailsFile))
            {
                try
                {
                    resultData.Details = System.IO.File.ReadAllText(detailsFile);
                }
                catch (Exception ex)
                {
                    resultData.Details = "Error: Details not loaded...\n\n" + ex.Message;
                }
            }
            // check for image (.png file
            string imageFile = getPathWithoutExtension(file) + ".png";
            if (System.IO.File.Exists(imageFile))
            {
                try
                {
                    resultData.Image = new Bitmap(imageFile);
                }
                catch (Exception ex)
                {
                    // ToDo: add default-image here???
                }
            }

            // return the final sample-object
            return resultData;
        }

        #endregion

        #region UI-Generation

        /// <summary>
        /// Creates the Sample board tab page.
        /// </summary>
        /// <param name="tabPageCaption">The tab page caption.</param>
        /// <param name="filePath">The file path.</param>
        /// <returns></returns>
        [Obsolete("Can be removed after new Data-Object is implemented...")]
        public static TabPage CreateSoundBoardTabPage(String tabPageCaption, String filePath)
        {
            TabPage returnPage = new TabPage();
            returnPage.Text = tabPageCaption;
            returnPage.BackColor = Color.White;
            BaseButtonPanel buttonPanel = new BaseButtonPanel(filePath);
            buttonPanel.BackColor = Color.Transparent;
            returnPage.Controls.Add(buttonPanel);
            returnPage.Controls[0].Dock = DockStyle.Fill;

            return returnPage;
        }

        /// <summary>
        /// Creates a sound board tab page.
        /// </summary>
        /// <param name="directoryItem">The directory item.</param>
        /// <returns>the Tab-Page for a Tab-Control</returns>
        public static TabPage CreateSoundBoardTabPage(SampleData directoryItem)
        {
            TabPage returnPage = new TabPage();
            returnPage.Text = directoryItem.Name;
            returnPage.BackColor = Color.White;
            List<SampleData> samples = directoryItem.GetChildItems(DataType.Sample);
            BaseButtonPanel buttonPanel = new BaseButtonPanel(samples);
            buttonPanel.BackColor = Color.Transparent;
            returnPage.Controls.Add(buttonPanel);
            returnPage.Controls[0].Dock = DockStyle.Fill;

            return returnPage;
        }

        /// <summary>
        /// Creates the Sample board button.
        /// </summary>
        /// <param name="filePath">The file path.</param>
        /// <returns></returns>
        [Obsolete("Can be removed after new Data-Object is implemented...")]
        public static Button CreateSoundBoardButton(String filePath, ref ToolTip controlToolTip)
        {
            // create a new button
            Button returnButton = new Button();
            // save filepath in tag property of the button
            returnButton.Tag = filePath;
            // get the Name-Base for the Soundfile (to find button-image and additional info)
            string tmpFileName = getPathWithoutExtension(filePath) + ".txt";
            // init value for Item-Name (Button-Text)
            string tmpItemDescription = getItemDescription(tmpFileName, createButtonText(filePath));
            // apply toolTip
            controlToolTip.SetToolTip(returnButton, tmpItemDescription);
            // check for button-image
            tmpFileName = getPathWithoutExtension(filePath) + ".png";
            if (System.IO.File.Exists(tmpFileName)) // we have an image-file
            {
                // load image for button
                returnButton.Image = new Bitmap(tmpFileName);
            }
            else // there is no image-file - just display the text
            {
                returnButton.Text = createButtonText(filePath);
                returnButton.Font = Properties.Settings.Default.Button_Font;
            }
            // set size and click-handler            
            returnButton.Size = Properties.Settings.Default.Button_Size;
            returnButton.Click += new EventHandler(returnButton_Click);
            returnButton.MouseDown += new MouseEventHandler(returnButton_MouseDown);
            // return the created button
            return returnButton;
        }

        /// <summary>
        /// Creates a sound board button.
        /// </summary>
        /// <param name="sample">The sample.</param>
        /// <param name="controlToolTip">The ToolTip that should handle the button.</param>
        /// <returns>the created Button, ready to use</returns>
        public static Button CreateSoundBoardButton(SampleData sample, ref ToolTip controlToolTip)
        {
            // create a new button
            Button returnButton = new Button();
            // save filepath in tag property of the button
            returnButton.Tag = sample.Path; // ToDo: switch to full object (?) --> has to be implemented in left and right click!
            // apply tooltip
            if (sample.Details.Trim() != string.Empty) // there are details add right-click info
            {
                controlToolTip.SetToolTip(returnButton, sample.ToolTip + "\n(right-click button for full info)");
            }
            else // just the tooltip
            {
                controlToolTip.SetToolTip(returnButton, sample.ToolTip);
            }
            // check for button-image
            if (sample.Image != null) // we have an image-file
            {
                // load image for button
                returnButton.Image = sample.Image;
            }
            else // there is no image-file - just display the name
            {
                returnButton.Text = sample.Name;
                returnButton.Font = Properties.Settings.Default.Button_Font;
            }
            // set size and click-handler            
            returnButton.Size = Properties.Settings.Default.Button_Size;
            returnButton.Click += new EventHandler(returnButton_Click);
            returnButton.MouseDown += new MouseEventHandler(returnButton_MouseDown);
            // return the created button
            return returnButton;
        }

        #endregion


        /// <summary>
        /// Handles the MouseDown event of the returnButton control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.MouseEventArgs"/> instance containing the event data.</param>
        static void returnButton_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                string tmpFileName = getPathWithoutExtension((String)((Button)sender).Tag) + ".txt";
                if (System.IO.File.Exists(tmpFileName))
                {
                    MessageBox.Show(System.IO.File.ReadAllText(tmpFileName), "Sample Info:", MessageBoxButtons.OK);
                }
            }
        }

        
        /// <summary>
        /// Gets the item description.
        /// </summary>
        /// <param name="filePath">The file path.</param>
        /// <param name="defaultText">The default text.</param>
        /// <returns></returns>
        [Obsolete("Can be removed after new Data-Object is implemented...")]
        private static string getItemDescription(string filePath, string defaultText)
        {
            string tmpItemDescription = string.Empty;
            if (System.IO.File.Exists(filePath)) // we have a text-file
            {
                // load data - first line only and add detail-info
                tmpItemDescription = System.IO.File.ReadAllLines(filePath)[0] + "\n(right-click button for full info)";
            }
            if (tmpItemDescription.Trim() == string.Empty)
            {
                tmpItemDescription = defaultText;
            }
            return tmpItemDescription;
        }

        /// <summary>
        /// Handles the Click event of the returnButton control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        static void returnButton_Click(object sender, EventArgs e)
        {
            String soundFile = (String)((Button)sender).Tag;
            if (checkFile(soundFile))
            {
                playSound(soundFile);
            }
        }

        /// <summary>
        /// Checks the file.
        /// </summary>
        /// <param name="path">The path.</param>
        /// <returns></returns>
        private static Boolean checkFile(String path)
        {
            Boolean valid = true;

            if (!System.IO.File.Exists(path))
            {
                MessageBox.Show(String.Format("File '{0}' not found.", path), "File not found", MessageBoxButtons.OK, MessageBoxIcon.Error);
                valid = false;
            }
            else if (String.Compare(System.IO.Path.GetExtension(path), ".wav", true) != 0)
            {
                MessageBox.Show(String.Format("File '{0}' is not a wav-File.", path), "Incorrect file format", MessageBoxButtons.OK, MessageBoxIcon.Error);
                valid = false;
            }

            return valid;
        }

        /// <summary>
        /// Plays the Sample.
        /// </summary>
        /// <param name="path">The path.</param>
        private static void playSound(String path)
        {
            using (SoundPlayer player = new SoundPlayer(path))
            {
                player.Play();
            }
        }

        /// <summary>
        /// Gets the path without extension.
        /// </summary>
        /// <param name="path">The input filepath.</param>
        /// <returns>the full path without file-extension</returns>
        private static string getPathWithoutExtension(string path)
        {
            return path.Substring(0, path.Length - System.IO.Path.GetExtension(path).Length);
        }

        /// <summary>
        /// Creates the Text for a Button from Filename and Path
        /// </summary>
        /// <param name="path">The input filename as full path.</param>
        /// <returns>the Text for a Button</returns>
        /// <remarks>coded by Dade, 2012-07-13</remarks>
        private static string createButtonText(string path)
        {
            // extract filename from input, insert spaces
            return InsertSpaces(System.IO.Path.GetFileNameWithoutExtension(path));
        }

        /// <summary>
        /// Inserts spaces for underscores and in front of capital letters (if not already there).
        /// </summary>
        /// <param name="inputText">The input text.</param>
        /// <returns>The text with spaces - rewritten based on user-settings</returns>
        /// <remarks>coded by Dade, 2012-07-13; last update 2012-07-13</remarks>
        public static string InsertSpaces(string inputText)
        {
            // save the input text as char-array for processing (optional: replace underscores with spaces)
            char[] tmpFilename;
            if (Properties.Settings.Default.ReWrite_Underscores) // replace active
            {
                tmpFilename = inputText.Replace("_", " ").ToCharArray();
            }
            else // replace not active
            {
                tmpFilename = inputText.ToCharArray();
            }
            // create string-builder for the result
            StringBuilder tmpResult = new StringBuilder();
            if (Properties.Settings.Default.ReWrite_ByCapitalLetter) // auto-spacing by capital letter
            {
                // init other temp-vars for processing
                int tmpCharCode; // ASCII-code of a char
                bool foundPossibleInsertPosition; // reminder for space-insert-detection
                char tmpCompareChar; // tmp var to compare a char
                // for each char in filename
                for (int cnt = 0; cnt < tmpFilename.Length; cnt++)
                {
                    // init tmp-var for insert-detection
                    foundPossibleInsertPosition = false;
                    // get ASCII-Code of char
                    tmpCharCode = (int)tmpFilename[cnt];
                    if ((tmpCharCode >= 65) && (tmpCharCode <= 90)) // we have a capital letter
                    {
                        foundPossibleInsertPosition = true;
                    }
                    // check if insert-position is not the first char
                    if (foundPossibleInsertPosition && (cnt > 0))
                    {
                        tmpCompareChar = tmpFilename[cnt - 1];
                        // if the position before is not already a space and no dash
                        if ((tmpCompareChar != ' ') && (tmpCompareChar != '-'))
                        {
                            // insert a space in the output
                            tmpResult.Append(" ");
                        }
                    }
                    // add the char to output
                    tmpResult.Append(tmpFilename[cnt]);
                }
            }
            else // no auto-spaces for capital letters
            {
                tmpResult.Append(tmpFilename); // just return the data
            }
            //
            return tmpResult.ToString();
        }

    }
}
